package cn.anecansaitin.whimsy.test.item.multi_anim;

import cn.anecansaitin.whimsy.Whimsy;
import cn.anecansaitin.whimsy.test.item.multi_anim.MultiAnimTest;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4f;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.constant.DataTickets;
import software.bernie.geckolib.core.animation.AnimationState;
import software.bernie.geckolib.model.DefaultedItemGeoModel;
import software.bernie.geckolib.model.GeoModel;
import software.bernie.geckolib.renderer.GeoItemRenderer;

import java.util.ArrayList;
import java.util.List;

public class MultiAnimTestRender extends GeoItemRenderer<MultiAnimTest> {
    private final List<GeoModel<MultiAnimTest>> models = new ArrayList<>();

    public MultiAnimTestRender() {
        super(new DefaultedItemGeoModel<MultiAnimTest>(Whimsy.resource("multi_anim_test")).withAltAnimations(Whimsy.resource("test_item")));
        models.add(model);
        models.add(new DefaultedItemGeoModel<MultiAnimTest>(Whimsy.resource("multi_anim_test2")).withAltAnimations(Whimsy.resource("test_item2")));
    }

    @Override
    public GeoModel<MultiAnimTest> getGeoModel() {
        ItemStack stack = getCurrentItemStack();
        int i = stack.getOrCreateTag().getInt("model");

        return switch (i) {
            case 1 -> models.get(1);
            default -> models.get(0);
        };
    }

    @Override
    public void actuallyRender(PoseStack poseStack, MultiAnimTest animatable, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
        if (!isReRender) {
            AnimationState<MultiAnimTest> animationState = new AnimationState<>(animatable, 0, 0, partialTick, false);
            long instanceId = getInstanceId(animatable);

            animationState.setData(DataTickets.TICK, animatable.getTick(this.currentItemStack));
            animationState.setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective);
            animationState.setData(DataTickets.ITEMSTACK, this.currentItemStack);
            animatable.getAnimatableInstanceCache().getManagerForId(instanceId).setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective);
            getGeoModel().addAdditionalStateData(animatable, instanceId, animationState::setData);
            getGeoModel().handleAnimations(animatable, instanceId, animationState);
        }

        this.modelRenderTranslations = new Matrix4f(poseStack.last().pose());
        defaultActuallyRender(poseStack, animatable, model, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha);
    }

    private void defaultActuallyRender(PoseStack poseStack, MultiAnimTest animatable, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
        updateAnimatedTextureFrame(animatable);

        for (GeoBone group : model.topLevelBones()) {
            renderRecursively(poseStack, animatable, group, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha);
        }
    }
}
/*public class MultiAnimTestRender extends BlockEntityWithoutLevelRenderer implements GeoRenderer<MultiAnimTest> {
    private final List<GeoModel<MultiAnimTest>> models = new ArrayList<>();
    protected final GeoRenderLayersContainer<MultiAnimTest> renderLayers = new GeoRenderLayersContainer<>(this);
    protected ItemStack currentItemStack;
    protected ItemDisplayContext renderPerspective;
    protected MultiAnimTest animatable;
    protected float scaleWidth = 1;
    protected float scaleHeight = 1;
    protected boolean useEntityGuiLighting = false;

    protected Matrix4f itemRenderTranslations = new Matrix4f();
    protected Matrix4f modelRenderTranslations = new Matrix4f();

    public MultiAnimTestRender() {
        this(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels());
    }

    public MultiAnimTestRender(BlockEntityRenderDispatcher dispatcher, EntityModelSet modelSet) {
        super(dispatcher, modelSet);

        models.add(new DefaultedItemGeoModel<MultiAnimTest>(Whimsy.resource("multi_anim_test")).withAltAnimations(Whimsy.resource("test_item")));
        models.add(new DefaultedItemGeoModel<MultiAnimTest>(Whimsy.resource("multi_anim_test")).withAltAnimations(Whimsy.resource("test_item2")));
    }

    @Override
    public GeoModel<MultiAnimTest> getGeoModel() {
        ItemStack stack = getCurrentItemStack();
        int i = stack.getOrCreateTag().getInt("model");

        return switch (i) {
            case 1 -> models.get(1);
            default -> models.get(0);
        };
    }

    @Override
    public MultiAnimTest getAnimatable() {
        return this.animatable;
    }

    public ItemStack getCurrentItemStack() {
        return this.currentItemStack;
    }

    public MultiAnimTestRender useAlternateGuiLighting() {
        this.useEntityGuiLighting = true;

        return this;
    }

    @Override
    public long getInstanceId(MultiAnimTest animatable) {
        return GeoItem.getId(this.currentItemStack);
    }

    @Override
    public ResourceLocation getTextureLocation(MultiAnimTest animatable) {
        return GeoRenderer.super.getTextureLocation(animatable);
    }

    @Override
    public List<GeoRenderLayer<MultiAnimTest>> getRenderLayers() {
        return this.renderLayers.getRenderLayers();
    }

    public MultiAnimTestRender addRenderLayer(GeoRenderLayer<MultiAnimTest> renderLayer) {
        this.renderLayers.addLayer(renderLayer);

        return this;
    }

    public MultiAnimTestRender withScale(float scale) {
        return withScale(scale, scale);
    }

    public MultiAnimTestRender withScale(float scaleWidth, float scaleHeight) {
        this.scaleWidth = scaleWidth;
        this.scaleHeight = scaleHeight;

        return this;
    }

    @Override
    public void preRender(PoseStack poseStack, MultiAnimTest animatable, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
        this.itemRenderTranslations = new Matrix4f(poseStack.last().pose());
        scaleModelForRender(this.scaleWidth, this.scaleHeight, poseStack, animatable, model, isReRender, partialTick, packedLight, packedOverlay);

        if (!isReRender) poseStack.translate(0.5f, 0.51f, 0.5f);
    }

    @Override
    public void renderByItem(ItemStack stack, ItemDisplayContext transformType, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
        this.animatable = (MultiAnimTest) stack.getItem();
        this.currentItemStack = stack;
        this.renderPerspective = transformType;

        if (transformType == ItemDisplayContext.GUI) {
            renderInGui(transformType, poseStack, bufferSource, packedLight, packedOverlay);
        } else {
            RenderType renderType = getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, Minecraft.getInstance().getFrameTime());
            VertexConsumer buffer = ItemRenderer.getFoilBufferDirect(bufferSource, renderType, false, this.currentItemStack != null && this.currentItemStack.hasFoil());

            defaultRender(poseStack, this.animatable, bufferSource, renderType, buffer, 0, Minecraft.getInstance().getFrameTime(), packedLight);
        }
    }

    protected void renderInGui(ItemDisplayContext transformType, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
        MultiBufferSource.BufferSource defaultBufferSource = bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 ? bufferSource2 : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource();
        RenderType renderType = getRenderType(this.animatable, getTextureLocation(this.animatable), defaultBufferSource, Minecraft.getInstance().getFrameTime());
        VertexConsumer buffer = ItemRenderer.getFoilBufferDirect(bufferSource, renderType, true, this.currentItemStack != null && this.currentItemStack.hasFoil());

        poseStack.pushPose();

        if (this.useEntityGuiLighting) {
            Lighting.setupForEntityInInventory();
        } else {
            Lighting.setupForFlatItems();
        }

        defaultRender(poseStack, this.animatable, defaultBufferSource, renderType, buffer, 0, Minecraft.getInstance().getFrameTime(), packedLight);
        defaultBufferSource.endBatch();
        RenderSystem.enableDepthTest();
        Lighting.setupFor3DItems();
        poseStack.popPose();
    }

    @Override
    public void actuallyRender(PoseStack poseStack, MultiAnimTest animatable, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
        if (!isReRender) {
            AnimationState<MultiAnimTest> animationState = new AnimationState<>(animatable, 0, 0, partialTick, false);
            long instanceId = getInstanceId(animatable);

            animationState.setData(DataTickets.TICK, animatable.getTick(this.currentItemStack));
            animationState.setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective);
            animationState.setData(DataTickets.ITEMSTACK, this.currentItemStack);
            animatable.getAnimatableInstanceCache().getManagerForId(instanceId).setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective);
            getGeoModel().addAdditionalStateData(animatable, instanceId, animationState::setData);
            getGeoModel().handleAnimations(animatable, instanceId, animationState);
        }

        this.modelRenderTranslations = new Matrix4f(poseStack.last().pose());

        GeoRenderer.super.actuallyRender(poseStack, animatable, model, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha);
    }

    @Override
    public void renderRecursively(PoseStack poseStack, MultiAnimTest animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
        if (bone.isTrackingMatrices()) {
            Matrix4f poseState = new Matrix4f(poseStack.last().pose());

            bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations));
            bone.setLocalSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.itemRenderTranslations));
        }

        GeoRenderer.super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha);
    }

    @Override
    public void updateAnimatedTextureFrame(MultiAnimTest animatable) {
        AnimatableTexture.setAndUpdate(getTextureLocation(animatable));
    }

    @Override
    public void fireCompileRenderLayersEvent() {
//        NeoForge.EVENT_BUS.post(new GeoRenderEvent.Item.CompileRenderLayers(this));
    }

    @Override
    public boolean firePreRenderEvent(PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) {
//        return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Item.Pre(this, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled();
        return false;
    }

    @Override
    public void firePostRenderEvent(PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) {
//        NeoForge.EVENT_BUS.post(new GeoRenderEvent.Item.Post(this, poseStack, model, bufferSource, partialTick, packedLight));
    }
}*/
